/*
 * Copyright (c) 2025 Industrial Software Feature Database
 */
package com.comac.ins.common.biz.event;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.comac.ins.common.biz.domain.db.BizEventInfo;
import com.comac.ins.common.biz.domain.model.BizEvent;
import com.comac.ins.common.biz.domain.vo.BizEventInfoVo;
import com.comac.ins.common.biz.enums.BizEventStatusEnum;
import com.comac.ins.common.biz.mapper.BizEventMapper;
import com.comac.ins.common.biz.utils.BizAssertUtil;
import com.comac.ins.common.core.constant.Constants;
import com.comac.ins.common.core.utils.SpringUtils;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;
import org.slf4j.helpers.MessageFormatter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.text.MessageFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

/**
 * BizEventService
 *
 * @author zhanghongyi
 * @date 2025-01-23
 * @description BizEventService
 */
@Component
@Slf4j
public class BizEventService {

    @Autowired
    public void setBizEventMapper(BizEventMapper bizEventMapper) {
        this.bizEventMapper = bizEventMapper;
    }

    private static BizEventMapper bizEventMapper;

    public static List<BizEventInfoVo> queryEventInfoByIds(List<Long> ids) {
        BizAssertUtil.notEmpty(ids, "ids is empty");
        return bizEventMapper.selectVoBatchIds(ids);
    }

    public static BizEventInfoVo queryEventInfoById(Long id) {
        BizAssertUtil.notNull(id, "id is null");
        return bizEventMapper.selectVoById(id);
    }

    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    protected BizEventInfo initEventInfo(BizEvent<?> event) {
        cleanOldEventInfo();
        BizAssertUtil.notNull(event, "event is null");
        BizEventInfo eventInfo = new BizEventInfo();
        eventInfo.setEventType(event.getEventType().getCode());
        eventInfo.setEventClass(event.getEventPayload().getClass().getName());
        eventInfo.setTraceId(event.getTraceId());
        eventInfo.setStatus(BizEventStatusEnum.INIT.getCode());
        eventInfo.setAsync(event.isAsync());
        eventInfo.setCreateTime(new Date());
        eventInfo.setUpdateTime(new Date());
        BizAssertUtil.isTrue(bizEventMapper.insert(eventInfo) == 1, "insert bizEventInfo fail");
        event.setEventInfo(eventInfo);
        return eventInfo;
    }

    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    protected void updateEventInfo(BizEventInfo eventInfo) {
        BizAssertUtil.notNull(eventInfo, "eventInfo is null");
        eventInfo.setUpdateTime(new Date());
        BizAssertUtil.isTrue(bizEventMapper.updateById(eventInfo) > 0, "update bizEventInfo fail");
    }

    public static void updateCurrentMsg(String format, Object... args) {
        BizEvent<?> event = BizEventUtil.getEvent();
        if (null != event) {
            try {
                String currentMsg = MessageFormatter.basicArrayFormat(format, args);
                log.info("updateCurrentMsg:{}", currentMsg);
                BizAssertUtil.notNull(event.getEventInfo(), "eventInfo is null");
                event.getEventInfo().setUpdateTime(new Date());
                BizEventUtil.setCurrentMsg(event.getEventInfo(), currentMsg);
                SpringUtils.getBean(BizEventService.class).updateEventInfo(event.getEventInfo());
            } catch (Exception e) {
                log.error("updateCurrentMsg error:{}", e.getMessage());
            }
        }
    }

    /**
     * 发布事件
     */
    public static <M> Long publishEvent(BizEvent<M> event) {
        if (null == event.getTraceId()) {
            event.setTraceId(MDC.get(Constants.TRACE_ID));
        }
        SpringUtils.getBean(BizEventService.class).initEventInfo(event);
        SpringUtils.context().publishEvent(event);
        return event.getEventInfo().getId();
    }

    /**
     * 发布事件
     */
    public static <M> Long publishEvent(M payload) {
        BizEvent<M> event = new BizEvent<>(payload);
        event.setTraceId(MDC.get(Constants.TRACE_ID));
        SpringUtils.getBean(BizEventService.class).initEventInfo(event);
        SpringUtils.context().publishEvent(event);
        return event.getEventInfo().getId();
    }

    protected void cleanOldEventInfo() {
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.MONTH, -1);
        LambdaQueryWrapper<BizEventInfo> condition = new LambdaQueryWrapper<BizEventInfo>()
            .lt(BizEventInfo::getCreateTime, calendar.getTime());
        int delCnt = bizEventMapper.delete(condition);
        if (delCnt > 0) {
            log.info("cleanOldEventInfo:{} items", delCnt);
        }
    }

}
